#!/usr/bin/env python
#coding: utf-8

import sys, os, time, atexit, string
import signal

class Daemonit:
    def __init__(self, 
        pidfile, 
        stdin='/dev/null', 
        stdout_logfile='/dev/null', 
        stderr_logfile='/dev/null'
    ):
        #需要获取调试信息，改为stdin='/dev/stdin', stdout='/dev/stdout', stderr='/dev/stderr'，以root身份运行
        self.stdin = stdin
        self.stdout_logfile = stdout_logfile
        self.stderr_logfile = stderr_logfile
        self.pidfile = pidfile
    
    def daemonize(self):
        try:
            # 第一次fork，生成子进程，脱离控制终端
            pid = os.fork()
            if pid > 0:
                sys.exit(0)    #退出父进程
        except OSError, e:
            sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror))
            sys.exit(1)
        
        os.chdir("/")    
        os.setsid()      
        os.umask(0)      
        try:
            #第二次fork，可以禁止进程再次打开终端  
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError, e:
            sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror))
            sys.exit(1)

        #重定向文件描述符
        sys.stdout.flush()
        sys.stderr.flush()
        si = file(self.stdin, 'r')
        so = file(self.stdout_logfile, 'a+')
        se = file(self.stderr_logfile, 'a+', 0)
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())
        ## atexit注册退出函数，main函数执行完毕后回调.
        ## atexit.register(self.del_pidfile)
        pid = str(os.getpid())
        file(self.pidfile,'w+').write('%s\n' % pid)
        sys.stdout.write('pid: %d' % os.getpid())

    def get_pid(self):
        return os.get_pid()

    def del_pidfile(self):
        os.remove(self.pidfile)

    def start(self, worker, cfg_opts):
        print('daemon starting...')
        #检查pid文件是否存在以探测是否存在进程  
        try:
            pf = file(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None

        if pid:
            message = 'pidfile %s already exist. Daemon already running!\n'
            sys.stderr.write(message % self.pidfile)
            sys.exit(1)
        
        ## 创建守护进程, 并执行重载的run方法中的操作
        self.daemonize()
        worker(cfg_opts)

    def stop(self):
        try:
            ## 从pid文件中获取pid
            pf = file(self.pidfile,'r')
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None

        if not pid: 
            message = 'pidfile %s does not exist. Daemon not running!\n'  
            sys.stderr.write(message % self.pidfile)
            return False

        try:
            while 1:
                self.del_pidfile()
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)
        except OSError, e:
            e = str(e)
            if e.find('No such process') > 0:
                if os.path.exists(self.pidfile):
                    os.remove(self.pidfile)
            else:
                print str(e)
                sys.exit(1)
        return True

    def restart(self):
        self.stop()
        self.start()
